package com.mm.cloud.common.security.aspect;

import com.mm.cloud.common.core.exception.BaseException;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validator;
import jakarta.validation.executable.ExecutableValidator;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Set;

/**
 * 参数合法校验切面
 * SpringValidation是对hibernate validation的二次封装
 * hibernate validation是校验框架，是JSR303标准的实践结果
 *
 * @author mr
 * @since 2021-06-09
 */
@Component
@Aspect
@Order(1)
public class ParameterCheckAspect {

    @Autowired
    private Validator validator;

    @Pointcut("@annotation(com.mm.cloud.common.security.annotation.ParameterCheck)")
    public void parameterCheck() {
    }

    @Before("parameterCheck()")
    public void check(JoinPoint joinPoint) {
        Object[] parameters = joinPoint.getArgs();
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        ExecutableValidator executableValidator = validator.forExecutables();
        //校验方法上的参数
        Set<ConstraintViolation<Object>> constraintViolations = executableValidator.validateParameters(joinPoint.getTarget(), method, parameters);
        String methodErrorMessage = constraintViolations.stream().findFirst().map(ConstraintViolation::getMessage).orElse(null);
        if (StringUtils.isNotEmpty(methodErrorMessage)) {
            throw new BaseException(methodErrorMessage);
        }

        //校验dto
        for (Object parameter : parameters) {
            if (ObjectUtils.isEmpty(parameter)) {
                continue;
            }
            Set<ConstraintViolation<Object>> validateSet = validator.validate(parameter);
            String DtoErrorMessage = validateSet.stream().findFirst().map(ConstraintViolation::getMessage).orElse(null);
            if (StringUtils.isNotEmpty(DtoErrorMessage)) {
                throw new BaseException(DtoErrorMessage);
            }
        }
    }

}
